package urlutil

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"math/big"
	"net/http"
	"net/url"
	"reflect"
	"strconv"
	"strings"
	"time"

	"gitee.com/tomatomeatman/golang-repository/bricks/model/emity"
	"gitee.com/tomatomeatman/golang-repository/bricks/utils/ginutil"
	Log "github.com/cihub/seelog"
	"github.com/shopspring/decimal"
)

type UrlUtil struct{}

// 取头参数
func (UrlUtil) GetHeader(ctx ginutil.Context) map[string]string {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	result := map[string]string{}
	header := ctx.Request.Header
	for key, value := range header {
		if (nil == value) || (len(value) < 1) {
			continue
		}

		result[key] = value[0]
	}

	return result
}

/**
 * 取所有参数,并转换成对应实体属性类型(map[string]interface{})
 * @param ctx gin请求上下文
 * @param entity 实体对象
 * @return map[string]interface{}
 */
func (UrlUtil) AllParams(ctx ginutil.Context, entity interface{}) (map[string][]string, map[string]string, map[string][]string) {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	//-- 取头参数 --//
	headerParam := map[string][]string{}
	header := ctx.Request.Header
	for key, value := range header {
		if (nil == value) || (len(value) < 1) {
			continue
		}

		headerParam[key] = value
	}

	postParam := map[string]string{}

	//-- 取Post方式json参数 --//

	// 检查是否为post请求
	// if ctx.Request.Method != http.MethodPost {
	// 	w.WriteHeader(http.StatusMethodNotAllowed)
	// 	fmt.Fprintf(w, "invalid_http_method")
	// 	return
	// }

	br, _ := io.ReadAll(ctx.Request.Body)
	ctx.Request.Body.Close()
	ctx.Request.Body = io.NopCloser(bytes.NewBuffer(br))
	json.NewDecoder(bytes.NewBuffer(br)).Decode(&postParam)

	//-- 取Get参数 --//
	getParam := map[string][]string{}
	query := ctx.Request.URL.Query()
	for key, value := range query {
		if (nil == value) || (len(value) < 1) {
			continue
		}

		getParam[key] = value
	}

	//-- 取属性的参数 --//
	form := ctx.Request.Form
	if nil != form {
		for key, value := range form {
			if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
				continue
			}

			val, ok := getParam[key]
			if ok && (len(val) > 0) && (val[0] != "") {
				continue //如果已经存在则不覆盖
			}

			getParam[key] = value
		}
	}

	return headerParam, postParam, getParam
}

// 取所有参数(map[string]interface{})
func (uu UrlUtil) GetParamsAll(ctx ginutil.Context, addHeader bool) map[string]interface{} {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	params := make(map[string]interface{})

	//-- 取Post方式json参数 --//
	// 检查是否为post请求
	// if ctx.Request.Method != http.MethodPost {
	// 	w.WriteHeader(http.StatusMethodNotAllowed)
	// 	fmt.Fprintf(w, "invalid_http_method")
	// 	return
	// }

	br, _ := io.ReadAll(ctx.Request.Body)
	ctx.Request.Body.Close()
	ctx.Request.Body = io.NopCloser(bytes.NewBuffer(br))
	json.NewDecoder(bytes.NewBuffer(br)).Decode(&params)

	//-- 取头参数 --//
	if addHeader {
		header := ctx.Request.Header
		for key, value := range header {
			if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
				continue
			}

			val, ok := params[key]
			if ok && (val != "") {
				continue //如果已经存在则不覆盖
			}

			params[key] = value[0]
		}
	}

	//-- 取Get参数 --//
	query := ctx.Request.URL.Query()
	for key, value := range query {
		if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
			continue
		}

		val, ok := params[key]
		if ok && (val != "") {
			continue //如果已经存在则不覆盖
		}

		params[key] = value[0]
	}

	//-- 取属性的参数 --//
	form := ctx.Request.Form
	if nil != form {
		for key, value := range form {
			if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
				continue
			}

			val, ok := params[key]
			if ok && (val != "") {
				continue //如果已经存在则不覆盖
			}

			params[key] = value[0]
		}
	}

	return params
}

// 取所有参数,并转换成对应实体属性类型(map[string]interface{})
func (uu UrlUtil) GetParams(ctx ginutil.Context, entity interface{}) *emity.MsgEmity {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	params := make(map[string]string)

	//-- 取Post方式json参数 --//
	// 检查是否为post请求
	// if ctx.Request.Method != http.MethodPost {
	// 	w.WriteHeader(http.StatusMethodNotAllowed)
	// 	fmt.Fprintf(w, "invalid_http_method")
	// 	return
	// }

	br, _ := io.ReadAll(ctx.Request.Body)
	ctx.Request.Body.Close()
	ctx.Request.Body = io.NopCloser(bytes.NewBuffer(br))

	var tempMap map[string]interface{}
	if err := json.NewDecoder(bytes.NewBuffer(br)).Decode(&tempMap); err == nil {
		for key, value := range tempMap {
			params[key] = fmt.Sprintf("%v", value)
		}
	}

	//-- 取头参数 --//
	header := ctx.Request.Header
	for key, value := range header {
		if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
			continue
		}

		val, ok := params[key]
		if ok && (val != "") {
			continue //如果已经存在则不覆盖
		}

		params[key] = value[0]
	}

	//-- 取Get参数 --//
	query := ctx.Request.URL.Query()
	for key, value := range query {
		if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
			continue
		}

		val, ok := params[key]
		if ok && (val != "") {
			continue //如果已经存在则不覆盖
		}

		params[key] = value[0]
	}

	//-- 取属性的参数 --//
	form := ctx.Request.Form
	if nil != form {
		for key, value := range form {
			if (nil == value) || (len(value) < 1) || (strings.TrimSpace(value[0]) == "") {
				continue
			}

			val, ok := params[key]
			if ok && (val != "") {
				continue //如果已经存在则不覆盖
			}

			params[key] = value[0]
		}
	}

	return uu.Filter(params, entity)
}

// 过滤map中不存在结构体中的属性,并转换成对应类型(map[string]interface{})
func (uu UrlUtil) Filter(data map[string]string, entity interface{}) *emity.MsgEmity {
	if len(data) < 1 {
		return emity.MsgEmity{}.Err(1001, "待转换数据为空") //make(map[string]interface{})
	}

	var rve reflect.Value

	typeOf := reflect.TypeOf(entity)  //通过反射获取type定义
	if typeOf.Kind() == reflect.Ptr { //是否指针类型
		rve = reflect.ValueOf(entity).Elem() // 取得struct变量的指针
	} else if typeOf.String() == "reflect.Value" {
		if entity.(reflect.Value).Kind() == reflect.Ptr {
			rve = entity.(reflect.Value).Elem()
		} else if entity.(reflect.Value).Kind() == reflect.Struct {
			rve = entity.(reflect.Value)
		} else {
			rve = entity.(reflect.Value)
		}
	} else {
		rve = reflect.ValueOf(entity)
	}

	result := make(map[string]interface{})

	for k, v := range data {
		field := rve.FieldByName("G" + k)
		if !field.IsValid() {
			continue
		}

		vType := field.Type().Name()
		switch vType {
		case "int":
			val, _ := strconv.Atoi(v)
			result[k] = val
		case "string":
			result[k] = v
		case "int64":
			val, _ := strconv.ParseInt(v, 10, 64)
			result[k] = val
		case "time.Time":
			val, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
			result[k] = val
		case "Time":
			val, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
			result[k] = val
		case "time":
			val, _ := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local)
			result[k] = val
		case "float64":
			val, _ := strconv.ParseFloat(v, 64)
			result[k] = val
		case "Decimal":
			val, _ := decimal.NewFromString(v)
			result[k] = val
		case "*big.Float":
			val, _ := strconv.ParseFloat(v, 64)
			result[k] = big.NewFloat(val)
		default:
			Log.Error("'map过滤属性操作'发现无法识别的类型:" + vType)
			//result[k] = v
		}
	}

	return emity.MsgEmity{}.Success(result, "转换结束")
}

// func (uu UrlUtil) GetHearParams(ctx.Request) *emity.MsgEmity {

// 	//-- 取请求头参数 --//
// 	header := ctx.Request.Header
// 	//fmt.Println("Header全部数据:", header)
// 	//明确给定类型
// 	var acc []string = header[FirstUpper("token")]
// 	for _, n := range acc {
// 		fmt.Println("Accepth内容:", n)
// 	}

// 	return emity.MsgEmity{}.Success(9999, "map转换json字符串发生异常:")
// }

/**
 * 取请求头参数
 * ctx GinHttp上下文对象
 * name 参数名称
 * def 默认值
 */
func (uu UrlUtil) GetHearParam(ctx ginutil.Context, name string, def interface{}) interface{} {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	header := ctx.Request.Header

	v := header[uu.firstUpper(name)]
	if nil == v || len(v) < 1 || strings.TrimSpace(v[0]) == "" {
		if def == nil {
			def = ""
		}

		return def
	}

	if def == nil {
		def = ""
	}

	switch def.(type) {
	case string: // 将interface转为string字符串类型
		return strings.TrimSpace(v[0])
	case int:
		result, err := strconv.Atoi(v[0])
		if err != nil {
			return def
		}

		return result
	case int64:
		result, err := strconv.ParseInt(v[0], 10, 64)
		if err != nil {
			return 0
		}

		return result
	case time.Time:
		result, err := time.ParseInLocation("2006-01-02 15:04:05", v[0], time.Local)
		if err != nil {
			return def
		}

		return result
	case float64:
		result, err := strconv.ParseFloat(v[0], 64)
		if err != nil {
			return def
		}

		return result
	default:
		return strings.TrimSpace(v[0])
	}
}

/**
 * 取参数
 * ctx GinHttp上下文对象
 * entity 要转换的数据类型 无视(&entity或entity)
 */
func (uu UrlUtil) GetBody(ctx ginutil.Context, entity interface{}) *emity.MsgEmity {
	typeOf := reflect.TypeOf(entity) //通过反射获取type定义

	if typeOf.Kind() == reflect.Ptr { //是否指针类型
		typeOf = typeOf.Elem()
	}

	if typeOf.Kind() != reflect.Struct { //不属于结构体
		return UrlUtil{}.GetParams(ctx, entity)
	}

	result := reflect.New(typeOf).Interface() //创建同结构的指针,并转换成Interface{}, 注意不要使用reflect.New(typeOf).Elem().Interface()

	br, _ := io.ReadAll(ctx.Request.Body)
	ctx.Request.Body.Close()
	ctx.Request.Body = io.NopCloser(bytes.NewBuffer(br)) //写回
	json.NewDecoder(bytes.NewBuffer(br)).Decode(result)

	return emity.MsgEmity{}.Success(reflect.ValueOf(result).Elem().Interface(), "转换结束") //把指针转换到实际,否则会提示: interface{} is *xxx not xxx
}

/**
 * 取参数
 * ctx GinHttp上下文对象
 * name 参数名称
 * def 默认值
 */
func (uu UrlUtil) GetParam(ctx ginutil.Context, name string, def interface{}) interface{} {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	//-- 取头参数 --//
	result := ctx.Request.Header.Get(name)
	if result != "" {
		return uu.toInterface(result, def)
	}

	result = ctx.Request.Header.Get(uu.firstUpper(strings.ToLower(name))) //sCookie会被传递为Scookie
	if result != "" {
		return uu.toInterface(result, def)
	}

	//-- 取POST方法的参数 --//
	params := make(map[string]interface{})

	br, _ := io.ReadAll(ctx.Request.Body)
	ctx.Request.Body.Close()
	ctx.Request.Body = io.NopCloser(bytes.NewBuffer(br))

	json.NewDecoder(bytes.NewBuffer(br)).Decode(&params)
	temp, ok := params[name]
	if ok {
		return uu.toInterface(fmt.Sprint(temp), def)
	}

	temp, ok = params[uu.firstUpper(name)]
	if ok {
		return uu.toInterface(fmt.Sprint(temp), def)
	}

	//-- 取GET方法的参数 --//
	query := ctx.Request.URL.Query() // 获取请求的参数

	v := query[name]
	if nil != v && len(v) > 0 && strings.TrimSpace(v[0]) != "" {
		return uu.toInterface(v[0], def)
	}

	//-- 取属性的参数 --//
	result = query.Get(name)
	if result != "" {
		return uu.toInterface(result, def)
	}

	//-- 取form-data格式数据 --//
	result = ctx.Request.FormValue(name)
	if result != "" {
		return uu.toInterface(result, def)
	}

	result = ctx.PostForm(name)
	if result != "" {
		return uu.toInterface(result, def)
	}

	//-- 取后期传入的参数 --//
	result = ctx.Request.Form.Get(name)
	if result != "" {
		return uu.toInterface(result, def)
	}

	return def
}

// 字符串转接口
func (uu UrlUtil) toInterface(value string, def interface{}) interface{} {
	if (strings.TrimSpace(value) == "") && (def == nil) {
		return def
	}

	if def == nil {
		def = ""
	}

	switch def.(type) {
	case string: // 将interface转为string字符串类型
		return strings.TrimSpace(value)
	case int:
		result, err := strconv.Atoi(value)
		if err != nil {
			return def
		}

		return result
	case int64:
		result, err := strconv.ParseInt(value, 10, 64)
		if err != nil {
			return 0
		}

		return result
	case time.Time:
		result, err := time.ParseInLocation("2006-01-02 15:04:05", value, time.Local)
		if err != nil {
			return def
		}

		return result
	case float32:
		result, err := strconv.ParseFloat(value, 32)
		if err != nil {
			return def
		}

		return result //注意,返回去的也是float64,所以 xx.(Float32)会异常,应使用 xx.(Float64)
	case float64:
		result, err := strconv.ParseFloat(value, 64)
		if err != nil {
			return def
		}

		return result
	default:
		return strings.TrimSpace(value)
	}
}

/**
 * 取请求参数中的记录编号
 * ctx GinHttp上下文对象
 * idName 主键名称
 */
func (uu UrlUtil) GetParamToId(ctx ginutil.Context, idName string) interface{} {
	var id interface{}

	id = UrlUtil{}.GetParam(ctx, idName, "")
	if strings.TrimSpace(id.(string)) == "" {
		return nil
	}

	return id
}

/**
 * 取请求参数中的版本号
 * ctx GinHttp上下文对象
 * hasVersion (数据库表)是否有版本号
 */
func (uu UrlUtil) GetParamToVersion(ctx ginutil.Context, hasVersion bool, versionName string) int {
	var iVersion int

	if hasVersion {
		iVersion = UrlUtil{}.GetParam(ctx, versionName, -1).(int)
	} else {
		iVersion = int(^uint(0) >> 1) //integerutil.IntegerUtil{}.MaxInt()
	}

	return iVersion
}

/**
 * 增加请求属性
 * ctx GinHttp上下文对象
 * name 属性名
 * value 属性值
 */
func (uu UrlUtil) AddAttrib(ctx ginutil.Context, name string, value string) {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	form := ctx.Request.Form
	if nil == form {
		form = make(url.Values)
		ctx.Request.Form = form
	}

	form.Set(name, value)
}

/**
 * 获取请求属性
 * ctx GinHttp上下文对象
 * name 属性名
 * value 属性值
 */
func (uu UrlUtil) GetAttrib(ctx ginutil.Context, name string) string {
	ctx.Request.ParseForm() //警告:必须先 解析所有请求数据

	form := ctx.Request.Form
	if nil == form {
		return ""
	}

	return form.Get(name)
}

// /**
//  * 允许跨域访问
//  * w Http响应对象
//  */
// func (uu UrlUtil) SetupCORS(ctx ginutil.Context) {
// 	(*w).Header().Set("Access-Control-Allow-Origin", "*")
// 	(*w).Header().Set("Access-Control-Allow-Methods", "POST, ginutil.GET, OPTIONS, PUT, DELETE")
// 	(*w).Header().Set("Access-Control-Allow-Headers", "Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization")
// }

/**
 * 设置统一返回信息
 * w Http响应对象
 * me 统一信息
 */
func (uu UrlUtil) SetResponse(ctx ginutil.Context, me *emity.MsgEmity) {
	// buffer := &bytes.Buffer{}
	// encoder := json.NewEncoder(buffer)
	// encoder.SetEscapeHTML(false)

	// err := encoder.Encode(me)
	// if err != nil {
	// 	return
	// }

	ctx.JSONP(http.StatusOK, me)
}

// FirstUpper 字符串首字母大写
func (uu UrlUtil) firstUpper(s string) string {
	if s == "" {
		return ""
	}

	return strings.ToUpper(s[:1]) + s[1:]
}
